package utils

import (
	"errors"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/levigross/grequests"
)

const (
	UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"

	GET int = iota
	POST
	PUT
	DELETE
)

var (
	Methods = map[int]RequestsDoFunc{
		GET:    grequests.Get,
		POST:   grequests.Post,
		PUT:    grequests.Put,
		DELETE: grequests.Delete,
	}
	ErrRqType        = errors.New("错误的请求类型")
	ErrTimeOutHeader = errors.New("请求目标网站超时")
)

type (
	RequestsDoFunc func(url string, ro *grequests.RequestOptions) (rp *grequests.Response, e error)
	RequestFunc    func(rp *grequests.Response) (e error)
	Requester      struct {
		option      *grequests.RequestOptions
		requestFunc RequestFunc
		url         string
	}
)

func NewRequester() *Requester {
	return &Requester{
		option: &grequests.RequestOptions{
			UserAgent:      UserAgent,
			RequestTimeout: time.Second * 10,
		},
		requestFunc: nil,
	}
}

func (r *Requester) Url() string {
	return r.url
}

func (r *Requester) SetUrl(url string) {
	r.url = url
}

func (r *Requester) RequestFunc() RequestFunc {
	return r.requestFunc
}

func (r *Requester) SetRequestFunc(requestFunc RequestFunc) {
	r.requestFunc = requestFunc
}

func (r *Requester) Option() *grequests.RequestOptions {
	return r.option
}

func (r *Requester) SetOption(option *grequests.RequestOptions) {
	r.option = option
}

func (r *Requester) cHeckTimeOutErr(err error) error {
	if strings.Contains(err.Error(), "(Client.Timeout exceeded while awaiting headers)") {
		return ErrTimeOutHeader
	}
	return err
}

func (r *Requester) Request(method int) (err error) {
	var rp *grequests.Response
	doFunc, ok := Methods[method]
	if !ok {
		return ErrRqType
	}
	rp, err = doFunc(r.url, r.option)
	defer func() {
		_ = rp.Close()
	}()
	if err != nil {
		err = r.cHeckTimeOutErr(err)
		return
	}
	switch rp.StatusCode {
	case http.StatusNotFound, http.StatusForbidden, http.StatusBadGateway:
		return errors.New(http.StatusText(rp.StatusCode))
	case http.StatusInternalServerError:
		return fmt.Errorf("http statusCode=500,body is:%s", rp.Bytes())
	default:
	}
	err = r.requestFunc(rp)
	return
}
